from typing import Optional, List, Tuple
from datetime import datetime
from tortoise.exceptions import DoesNotExist, IntegrityError
from tortoise.expressions import Q
from app.models.models import News, Dictionary
from app.schemas.news import NewsCreate, NewsUpdate, NewsPaginationResponse


class NewsService:  # 咨询与公告类

    @staticmethod  # 静态方法
    async def create(news_data: NewsCreate) -> News:
        """
        创建咨询与公告
        """
        try:
            # 验证外键是否存在
            category = await Dictionary.get_or_none(id=news_data.category_id)
            if not category:
                raise ValueError("指定的分类不存在")
            news_dict = news_data.model_dump()
            news = await News.create(**news_dict)
            # print(news)

            return news
        except IntegrityError as e:
            raise ValueError(f"创建失败: {str(e)}") from e

    @staticmethod
    async def update(news_id: int, news_data: NewsUpdate) -> Optional[News]:
        """更新公告"""
        try:
            news = await News.get(id=news_id)
            if not news:
                raise ValueError("指定的公告不存在")
            news_dict = news_data.model_dump()
            await news.update_from_dict(news_dict)
            await news.save()
            return news
        except IntegrityError as e:
            raise ValueError(f"更新失败: {str(e)}") from e

    @staticmethod
    async def delete(news_id: int) -> bool:
        """删除公告"""
        try:
            news = await News.get(id=news_id)
            news.is_deleted = True
            await news.save()
            return True
        except DoesNotExist:
            raise ValueError("公告不存在")
        except IntegrityError as e:
            raise ValueError(f"删除失败: {str(e)}") from e

    @staticmethod
    async def get_news_list_with_total(skip: int = 0, limit: int = 10, category_id: Optional[int] = None,
                                       search: Optional[str] = None, is_top: Optional[bool] = None) -> Tuple[
        List[News], int]:
        """
        获取公告列表及总数

        Args:
            skip (int): 跳过的记录数，用于分页，默认为0
            limit (int): 返回的记录数限制，用于分页，默认为10
            category_id (Optional[int]): 分类ID，用于按分类筛选公告
            search (Optional[str]): 搜索关键词，用于按标题或摘要搜索
            is_top (Optional[bool]): 置顶状态，用于筛选置顶或非置顶公告

        Returns:
            Tuple[List[News], int]: 公告列表和总记录数的元组
        """
        try:
            query = News.filter(is_deleted=False)

            # 根据分类筛选
            if category_id is not None:
                query = query.filter(category_id=category_id)

            # 根据置顶状态筛选
            if is_top is not None:
                query = query.filter(is_top=is_top)

            # 根据标题或摘要搜索
            if search:
                query = query.filter(
                    Q(title__icontains=search) | Q(abstract__icontains=search)
                )

            # 排序：置顶优先，然后按创建时间倒序
            query = query.order_by('-is_top', '-created_at')

            # 获取总数
            total = await query.count()

            # 分页获取数据
            news_list = await query.offset(skip).limit(limit)
            return list(news_list), total
        except Exception as e:
            raise ValueError(f"获取公告列表失败: {str(e)}") from e

    @staticmethod
    async def get_news_by_id(news_id: int) -> News:
        """根据ID获取公告详情"""
        try:
            news = await News.get(id=news_id, is_deleted=False)
            return news
        except DoesNotExist:
            raise ValueError("公告不存在")
        except Exception as e:
            raise ValueError(f"获取公告详情失败: {str(e)}") from e

    @staticmethod
    async def search_news_with_total(keyword: str, skip: int = 0, limit: int = 10,
                                     category_id: Optional[int] = None) -> Tuple[List[News], int]:
        """搜索公告及总数"""
        try:
            query = News.filter(is_deleted=False)

            # 关键词搜索：标题、摘要、内容
            if keyword:
                query = query.filter(
                    Q(title__icontains=keyword) | Q(abstract__icontains=keyword) | Q(content__icontains=keyword)
                )

            # 分类筛选
            if category_id is not None:
                query = query.filter(category_id=category_id)

            # 排序
            query = query.order_by('-is_top', '-created_at')

            # 获取总数
            total = await query.count()

            # 分页获取数据
            news_list = await query.offset(skip).limit(limit)
            return list(news_list), total
        except Exception as e:
            raise ValueError(f"搜索公告失败: {str(e)}") from e


# 创建News实例
news_crud = NewsService()






